package com.summli.basic.class08;

import java.util.ArrayList;

/**
 *
 * 给定一棵二叉树的头节点head，返回这颗二叉树是不是搜索二叉树
 *
 * 搜索二叉树：中序遍历有序
 *
 * m1:中序遍历
 * m2:递归套路解
 *
 */
public class Code03_IsBST {
    public static class Node {
        public int value;
        public Node left;
        public Node right;

        public Node(int data) {
            this.value = data;
        }
    }

    // 比较器方法
    public static boolean isBST1(Node head) {
        if(head == null){
            return true;
        }
        ArrayList<Node> list = new ArrayList<>();
        mid(head,list);
        for (int i = 0; i < list.size()-1; i++) {
            if(list.get(i).value >= list.get(i+1).value){
                return false;
            }
        }
        return true;
    }

    private static void mid(Node head, ArrayList<Node> list) {
        if(head == null){
            return;
        }
        mid(head.left,list);
        list.add(head);
        mid(head.right, list);
    }

    //  上诉方法空间复杂度为O(n)，但是需要额外的空间复杂度

    public static class Info{
        public boolean isBST;
        public int min;
        public int max;

        public Info(boolean isBST, int min, int max) {
            this.isBST = isBST;
            this.min = min;
            this.max = max;
        }
    }

    public static boolean isBST2(Node head) {
        if(head == null){
            return true;
        }
        Info result = process(head);
        return result.isBST;
    }

    private static Info process(Node cur) {
        if(cur == null){
            return null;
        }
        Info leftInfo = process(cur.left);
        Info rightInfo = process(cur.right);
        int min = cur.value;
        int max = cur.value;
        if(leftInfo != null){
            min = Math.min(min, leftInfo.min);
            max = Math.max(max, leftInfo.max);
        }
        if(rightInfo != null){
            min = Math.min(min, rightInfo.min);
            max = Math.max(max, rightInfo.max);
        }
        boolean isBST = (leftInfo==null?true:(leftInfo.isBST && (cur.value>leftInfo.max)))
                && (rightInfo == null? true:(rightInfo.isBST && (cur.value<rightInfo.min)));
        return new Info(isBST,min,max);
    }

    // for test
    public static Node generateRandomBST(int maxLevel, int maxValue) {
        return generate(1, maxLevel, maxValue);
    }

    // for test
    public static Node generate(int level, int maxLevel, int maxValue) {
        if (level > maxLevel || Math.random() < 0.5) {
            return null;
        }
        Node head = new Node((int) (Math.random() * maxValue));
        head.left = generate(level + 1, maxLevel, maxValue);
        head.right = generate(level + 1, maxLevel, maxValue);
        return head;
    }

    public static void main(String[] args) {
        int maxLevel = 4;
        int maxValue = 100;
        int testTimes = 1000000;
        for (int i = 0; i < testTimes; i++) {
            Node head = generateRandomBST(maxLevel, maxValue);
            if (isBST1(head) != isBST2(head)) {
                System.out.println("Oops!");
            }
        }
        System.out.println("finish!");
    }

}
